#if UNITY_ANDROID
using System;
using GMME.Model.Rtm.Req;
using GMME.Model.Rtm.Result;
using UnityEngine;

namespace GMME
{
    class GameMediaEngineForAndroid : GameMediaEngine
    {
        private static readonly string GAMEMEDIAENGINE_PATH = "com.huawei.game.gmme.GameMediaEngine";

        private static readonly string UNITYPLAYER_PATH = "com.unity3d.player.UnityPlayer";

        private static GameMediaEngineForAndroid sInstance = new();

        private AndroidJavaClass gameMediaEngineClass;

        private AndroidJavaObject context;

        private AndroidJavaObject engine;

        private GameMediaEngineForAndroid()
        {
            try
            {
                gameMediaEngineClass = new AndroidJavaClass(GAMEMEDIAENGINE_PATH);
                context = new AndroidJavaClass(UNITYPLAYER_PATH).GetStatic<AndroidJavaObject>("currentActivity");
            }
            catch (Exception e)
            {
                Debug.LogException(e);
            }
        }

        public static GameMediaEngineForAndroid GetInstance()
        {
            if (sInstance == null)
            {
                sInstance = new();
            }

            return sInstance;
        }

        public GameMediaEngine CreateEngine(EngineCreateParams engineParams, IGameMMEEventHandler callBackHandler)
        {
            Debug.Log("GMMEEngine create start in");
            try
            {
                engine = gameMediaEngineClass.CallStatic<AndroidJavaObject>("create",
                    ConvertEngineCreateParams(engineParams), callBackHandler);
            }
            catch (Exception e)
            {
                Debug.LogException(e);
            }

            return sInstance;
        }

        public AndroidJavaObject ConvertEngineCreateParams(EngineCreateParams engineParams)
        {
            AndroidJavaObject parmas = new AndroidJavaObject("com.huawei.game.gmme.model.EngineCreateParams");
            parmas.Set("openId", engineParams.OpenId);
            parmas.Set("context", context);
            parmas.Set("clientId", engineParams.ClientId);
            parmas.Set("agcAppId", engineParams.AppId);
            parmas.Set("apiKey", engineParams.ApiKey);
            parmas.Set("logEnable", engineParams.LogEnable);
            if (engineParams.ClientSecret != null)
            {
                parmas.Set("clientSecret", engineParams.ClientSecret);
            }

            if (engineParams.CpAccessToken != null)
            {
                parmas.Set("cpAccessToken", engineParams.CpAccessToken);
            }

            if (engineParams.LogPath != null)
            {
                parmas.Set("logPath", engineParams.LogPath);
            }

            if (engineParams.LogSize > 0)
            {
                parmas.Set("logSize", engineParams.LogSize);
            }

            if (engineParams.CountryCode != null)
            {
                parmas.Set("countryCode", engineParams.CountryCode);
            }

            if (engineParams.Sign != null)
            {
                parmas.Set("sign", engineParams.Sign);
            }

            if (engineParams.Nonce != null)
            {
                parmas.Set("nonce", engineParams.Nonce);
            }

            if (engineParams.Timestamp != null)
            {
                parmas.Set("timestamp", engineParams.Timestamp);
            }

            return parmas;
        }

        public AndroidJavaObject ConvertVoiceParam(VoiceParam voiceParam)
        {
            AndroidJavaObject parmas = new AndroidJavaObject("com.huawei.game.gmme.model.VoiceParam");
            parmas.Set("languageCode", voiceParam.LanguageCode);
            return parmas;
        }

        public void DestroyEngine()
        {
            gameMediaEngineClass.CallStatic("destroy");
        }

        public override void JoinTeamRoom(string roomId)
        {
            engine.Call("joinTeamRoom", roomId);
        }

        public override void JoinNationalRoom(string roomId, int roleType)
        {
            engine.Call("joinNationalRoom", roomId, roleType);
        }

        public override void JoinRangeRoom(string roomId)
        {
            engine.Call("joinRangeRoom", roomId);
        }

        public override void SwitchRoom(string roomId)
        {
            engine.Call("switchRoom", roomId);
        }

        public override void LeaveRoom(string roomId, string ownerId)
        {
            engine.Call("leaveRoom", roomId, ownerId);
        }

        public override void TransferOwner(string roomId, string ownerId)
        {
            engine.Call("transferOwner", roomId, ownerId);
        }

        public override int EnableMic(bool isEnabled)
        {
            return engine.Call<int>("enableMic", isEnabled);
        }


        public override void MutePlayer(string roomId, string openId, bool isMuted)
        {
            engine.Call("mutePlayer", roomId, openId, isMuted);
        }

        public override void MuteAllPlayers(string roomId, bool isMuted)
        {
            engine.Call("muteAllPlayers", roomId, isMuted);
        }

        public override Room GetRoom(string roomId)
        {
            AndroidJavaObject javaObject = engine.Call<AndroidJavaObject>("getRoom", roomId);
            return Room.ConvertRoom(javaObject);
        }

        public override void EnableSpeakersDetection(string roomId, int interval)
        {
            engine.Call("enableSpeakersDetection", roomId, interval);
        }

        public override void ForbidAllPlayers(string roomId, bool isForbidden)
        {
            engine.Call("forbidAllPlayers", roomId, isForbidden);
        }

        public override void ForbidPlayer(string roomId, string openId, bool isForbidden)
        {
            engine.Call("forbidPlayer", roomId, openId, isForbidden);
        }

        public override int EnableVoiceConversion(string roomId, int voiceType)
        {
            AndroidJavaClass voiceTypeClass = new AndroidJavaClass("com.huawei.game.common.constants.VoiceType");
            AndroidJavaObject voiceTypeObject = voiceTypeClass.CallStatic<AndroidJavaObject>("fromValue", voiceType);
            return engine.Call<int>("enableVoiceConversion", roomId, voiceTypeObject);
        }

        public override int GetVoiceConversionType(string roomId)
        {
            AndroidJavaObject javaObject = engine.Call<AndroidJavaObject>("getVoiceConversionType", roomId);
            return javaObject.Call<int>("getValue");
        }

        public override int EnableEarsBack(bool enable)
        {
            return engine.Call<int>("enableEarsBack", enable);
        }

        public override bool IsEarsBackEnable()
        {
            return engine.Call<bool>("isEarsBackEnable");
        }

        public override void StartRecordAudioToText(VoiceParam voiceParam)
        {
            engine.Call("startRecordAudioToText", ConvertVoiceParam(voiceParam));
        }

        public override void StopRecordAudioToText()
        {
            engine.Call("stopRecordAudioToText");
        }

        public override void StartRecordAudioMsg(string filePath, int voiceType)
        {
            Debug.Log("StartRecordAudioMsgWithVoiceType is called in the android sdk");
            AndroidJavaClass voiceTypeClass = new AndroidJavaClass("com.huawei.game.common.constants.VoiceType");
            AndroidJavaObject voiceTypeObject = voiceTypeClass.CallStatic<AndroidJavaObject>("fromValue", voiceType);
            engine.Call("startRecordAudioMsg", filePath, voiceTypeObject);
        }

        public override void StartRecordAudioMsg(string filePath)
        {
            Debug.Log("StartRecordAudioMsg is called in the android sdk");
            engine.Call("startRecordAudioMsg", filePath);
        }

        public override void StopRecordAudioMsg()
        {
            Debug.Log("StopRecordAudioMsg is called in the android sdk");
            engine.Call("stopRecordAudioMsg");
        }

        public override void UploadAudioMsgFile(string filePath, int msTimeOut)
        {
            Debug.Log("UploadAudioMsgFile is called in the android sdk");
            engine.Call("uploadAudioMsgFile", filePath, msTimeOut);
        }

        public override void DownloadAudioMsgFile(string fileId, string filePath, int msTimeOut)
        {
            Debug.Log("DownloadAudioMsgFile is called in the android sdk");
            engine.Call("downloadAudioMsgFile", fileId, filePath, msTimeOut);
        }

        public override AudioMsgFileInfo GetAudioMsgFileInfo(string filePath)
        {
            Debug.Log("GetAudioMsgFileInfo is called in the android sdk");
            AndroidJavaObject javaObject = engine.Call<AndroidJavaObject>("getAudioMsgFileInfo", filePath);
            return AudioMsgFileInfo.ConvertAudioMsgFileInfo(javaObject);
        }

        public override void PlayAudioMsg(string filePath)
        {
            Debug.Log("PlayAudioMsg is called in the android sdk");
            engine.Call("playAudioMsg", filePath);
        }

        public override void StopPlayAudioMsg()
        {
            Debug.Log("StopPlayAudioMsg is called in the android sdk");
            engine.Call("stopPlayAudioMsg");
        }

        public override void StartDetectAudioFile(string fileId)
        {
            Debug.Log("StartDetectAudioFile is called in the android sdk");
            engine.Call("startDetectAudioFile", fileId);
        }

        public override int PlayLocalAudioClip(LocalAudioInfo localAudioInfo)
        {
            Debug.Log("PlayLocalAudioClip is called in the android sdk");
            return engine.Call<int>("playLocalAudioClip", ConvertVoiceLocalAudioInfo(localAudioInfo));
        }

        public AndroidJavaObject ConvertVoiceLocalAudioInfo(LocalAudioInfo localAudioInfo)
        {
            AndroidJavaObject parmas = new AndroidJavaObject("com.huawei.game.gmme.model.LocalAudioInfo");
            parmas.Set("soundId", localAudioInfo.SoundId);
            parmas.Set("filePath", localAudioInfo.FilePath);
            parmas.Set("loop", localAudioInfo.Loop);
            parmas.Set("volume", localAudioInfo.Volume);
            return parmas;
        }

        public override int StopLocalAudioClip(int soundId)
        {
            Debug.Log("StopLocalAudioClip is called in the android sdk");
            return engine.Call<int>("stopLocalAudioClip", soundId);
        }

        public override int StopAllLocalAudioClips()
        {
            Debug.Log("StopAllLocalAudioClips is called in the android sdk");
            return engine.Call<int>("stopAllLocalAudioClips");
        }

        public override int PauseLocalAudioClip(int soundId)
        {
            Debug.Log("PauseLocalAudioClip is called in the android sdk");
            return engine.Call<int>("pauseLocalAudioClip", soundId);
        }

        public override int PauseAllLocalAudioClips()
        {
            Debug.Log("PauseAllLocalAudioClips is called in the android sdk");
            return engine.Call<int>("pauseAllLocalAudioClips");
        }

        public override int ResumeLocalAudioClip(int soundId)
        {
            Debug.Log("ResumeLocalAudioClip is called in the android sdk");
            return engine.Call<int>("resumeLocalAudioClip", soundId);
        }

        public override int ResumeAllLocalAudioClips()
        {
            Debug.Log("ResumeAllLocalAudioClips is called in the android sdk");
            return engine.Call<int>("resumeAllLocalAudioClips");
        }

        public override int GetVolumeOfLocalAudioClip(int soundId)
        {
            Debug.Log("GetVolumeOfLocalAudioClip is called in the android sdk");
            return engine.Call<int>("getVolumeOfLocalAudioClip", soundId);
        }

        public override int GetLocalAudioClipsVolume()
        {
            Debug.Log("GetLocalAudioClipsVolume is called in the android sdk");
            return engine.Call<int>("getLocalAudioClipsVolume");
        }

        public override int SetVolumeOfLocalAudioClip(int soundId, int volume)
        {
            Debug.Log("SetVolumeOfLocalAudioClip is called in the android sdk");
            return engine.Call<int>("setVolumeOfLocalAudioClip", soundId, volume);
        }

        public override int SetLocalAudioClipsVolume(int volume)
        {
            Debug.Log("SetLocalAudioClipsVolume is called in the android sdk");
            return engine.Call<int>("setLocalAudioClipsVolume", volume);
        }


        public override int SetAudioRecvRange(int range)
        {
            Debug.Log("SetAudioRecvRange is called in the android sdk");
            return engine.Call<int>("setAudioRecvRange", range);
        }


        public override int UpdateSelfPosition(SelfPosition selfPosition)
        {
            Debug.Log("UpdateSelfPosition is called in the android sdk");
            return engine.Call<int>("updateSelfPosition", ConvertSelfPosition(selfPosition));
        }

        public override int UpdateRemotePosition(RemotePlayerPosition[] positions)
        {
            Debug.Log("UpdateRemotePosition is called in the android sdk");
            return engine.Call<int>("updateRemotePosition", ConvertToListObject(positions));
        }

        public override void ClearAllRemotePositions()
        {
            Debug.Log("ClearAllRemotePositions is called in the android sdk");
            engine.Call<int>("clearAllRemotePositions");
        }

        public override void ClearRemotePlayerPosition(string openId)
        {
            Debug.Log("ClearRemotePlayerPosition is called in the android sdk");
            engine.Call<int>("clearRemotePlayerPosition", openId);
        }

        public override int InitSpatialSound()
        {
            Debug.Log("InitSpatialSound is called in the android sdk");
            return engine.Call<int>("initSpatialSound");
        }

        public override int EnableSpatialSound(string roomId, bool enable)
        {
            Debug.Log("EnableSpatialSound is called in the android sdk");
            return engine.Call<int>("enableSpatialSound", roomId, enable);
        }

        public override bool IsEnableSpatialSound(string roomId)
        {
            return engine.Call<bool>("isEnableSpatialSound", roomId);
        }

        private AndroidJavaObject ConvertSelfPosition(SelfPosition selfPosition)
        {
            AndroidJavaObject axisObj = new AndroidJavaObject("com.huawei.game.gmme.model.Axis");
            AndroidJavaObject positionObj = new AndroidJavaObject("com.huawei.game.gmme.model.PlayerPosition");
            AndroidJavaObject parmas = new AndroidJavaObject("com.huawei.game.gmme.model.SelfPosition");
            SetAxisArray(axisObj, selfPosition.Axis.Forward, "setForward");
            SetAxisArray(axisObj, selfPosition.Axis.Right, "setRight");
            SetAxisArray(axisObj, selfPosition.Axis.Up, "setUp");
            positionObj.Set("right", selfPosition.Position.Right);
            positionObj.Set("up", selfPosition.Position.Up);
            positionObj.Set("forward", selfPosition.Position.Forward);
            parmas.Set("axis", axisObj);
            parmas.Set("position", positionObj);
            return parmas;
        }

        private void SetAxisArray(AndroidJavaObject axisObj, float[] data, string methodName)
        {
            IntPtr jAryPtr = AndroidJNIHelper.ConvertToJNIArray(data);
            jvalue[] blah = new jvalue[1];
            blah[0].l = jAryPtr;

            IntPtr methodId = AndroidJNIHelper.GetMethodID(axisObj.GetRawClass(), methodName);
            AndroidJNI.CallVoidMethod(axisObj.GetRawObject(), methodId, blah);
        }


        private AndroidJavaObject ConvertToListObject(RemotePlayerPosition[] positions)
        {
            AndroidJavaObject list = new AndroidJavaObject("java.util.ArrayList");
            foreach (RemotePlayerPosition remotePlayerPosition in positions)
            {
                AndroidJavaObject remoteObj = new AndroidJavaObject("com.huawei.game.gmme.model.RemotePlayerPosition");
                AndroidJavaObject positionObj = new AndroidJavaObject("com.huawei.game.gmme.model.PlayerPosition");
                positionObj.Set("right", remotePlayerPosition.Position.Right);
                positionObj.Set("up", remotePlayerPosition.Position.Up);
                positionObj.Set("forward", remotePlayerPosition.Position.Forward);
                remoteObj.Set("openId", remotePlayerPosition.OpenId);
                remoteObj.Set("position", positionObj);
                list.Call<bool>("add", remoteObj);
            }

            return list;
        }

        #region rtm

        /**
         * 订阅RTM频道
         *
         * @param req 订阅RTM频道请求对象
         */
        public override void SubscribeRtmChannel(SubscribeRtmChannelReq req)
        {
            Debug.Log("SubscribeRtmChannel is called in the android sdk");
            engine.Call("subscribeRtmChannel", SubscribeRtmChannelReq.ConvertSubscribeRtmChannelReq(req));
        }

        /**
         * 取消订阅RTM频道
         *
         * @param req 取消订阅RTM频道请求对象
         */
        public override void UnSubscribeRtmChannel(UnSubscribeRtmChannelReq req)
        {
            Debug.Log("UnSubscribeRtmChannel is called in the android sdk");
            engine.Call("unSubscribeRtmChannel", UnSubscribeRtmChannelReq.ConvertUnSubscribeRtmChannelReq(req));
        }

        /**
         * 查询已订阅RTM频道信息
         *
         * @return 已订阅频道结果
         */
        public override GetRtmSubscribedChannelInfoResult GetRtmSubscribedChannelInfo()
        {
            Debug.Log("GetRtmSubscribedChannelInfo is called in the android sdk");
            AndroidJavaObject javaObject = engine.Call<AndroidJavaObject>("getRtmSubscribedChannelInfo");
            return GetRtmSubscribedChannelInfoResult.ConvertGetRtmSubscribedChannelInfoResult(javaObject);
        }

        /**
         * 查询RTM频道信息
         *
         * @param req 查询RTM频道信息请求对象
         */
        public override void GetRtmChannelInfo(GetRtmChannelInfoReq req)
        {
            Debug.Log("GetRtmChannelInfo is called in the android sdk");
            engine.Call("getRtmChannelInfo", GetRtmChannelInfoReq.ConvertGetRtmChannelInfoReq(req));
        }

        /**
         * 发布RTM频道信息
         *
         * @param req 发布RTM频道信息请求对象
         * @return 客户端本地生成的 clientMsgId
         */
        public override string PublishRtmChannelMessage(PublishRtmChannelMessageReq req)
        {
            Debug.Log("PublishRtmChannelMessage is called in the android sdk");
            var result = engine.Call<string>("publishRtmChannelMessage",
                PublishRtmChannelMessageReq.ConvertPublishRtmChannelMessageReq(req));
            return result;
        }

        /**
         * 发布RTM点对点信息
         *
         * @param req 发布RTM点对点信息请求对象
         * @return 客户端本地生成的 clientMsgId
         */
        public override string PublishRtmPeerMessage(PublishRtmPeerMessageReq req)
        {
            Debug.Log("PublishRtmPeerMessage is called in the android sdk");
            var result = engine.Call<string>("publishRtmPeerMessage",
                PublishRtmPeerMessageReq.ConvertPublishRtmPeerMessageReq(req));
            return result;
        }

        /**
         * 设置RTM频道内玩家属性
         *
         * @param req 设置RTM频道内玩家属性请求对象
         */
        public override void SetRtmChannelPlayerProperties(SetRtmChannelPlayerPropertiesReq req)
        {
            Debug.Log("SetRtmChannelPlayerProperties is called in the android sdk");
            engine.Call("setRtmChannelPlayerProperties",
                SetRtmChannelPlayerPropertiesReq.ConvertSetRtmChannelPlayerPropertiesReq(req));
        }

        /**
         * 查询RTM频道内玩家属性
         *
         * @param req 查询RTM频道内玩家属性请求对象
         */
        public override void GetRtmChannelPlayerProperties(GetRtmChannelPlayerPropertiesReq req)
        {
            Debug.Log("GetRtmChannelPlayerProperties is called in the android sdk");
            engine.Call("getRtmChannelPlayerProperties",
                GetRtmChannelPlayerPropertiesReq.ConvertGetRtmChannelPlayerPropertiesReq(req));
        }

        /**
         * 删除RTM频道内玩家属性
         *
         * @param req 删除RTM频道内玩家属性请求对象
         */
        public override void DeleteRtmChannelPlayerProperties(DeleteRtmChannelPlayerPropertiesReq req)
        {
            Debug.Log("DeleteRtmChannelPlayerProperties is called in the android sdk");
            engine.Call("deleteRtmChannelPlayerProperties",
                DeleteRtmChannelPlayerPropertiesReq.ConvertDeleteRtmChannelPlayerPropertiesReq(req));
        }

        /**
         * 设置RTM频道属性
         *
         * @param req 设置RTM频道属性请求对象
         */
        public override void SetRtmChannelProperties(SetRtmChannelPropertiesReq req)
        {
            Debug.Log("SetRtmChannelProperties is called in the android sdk");
            engine.Call("setRtmChannelProperties", SetRtmChannelPropertiesReq.ConvertSetRtmChannelPropertiesReq(req));
        }

        /**
         * 查询RTM频道属性
         *
         * @param req 查询RTM频道属性请求对象
         */
        public override void GetRtmChannelProperties(GetRtmChannelPropertiesReq req)
        {
            Debug.Log("GetRtmChannelProperties is called in the android sdk");
            engine.Call("getRtmChannelProperties", GetRtmChannelPropertiesReq.ConvertGetRtmChannelPropertiesReq(req));
        }

        /**
         * 删除RTM频道属性
         *
         * @param req 删除RTM频道属性请求对象
         */
        public override void DeleteRtmChannelProperties(DeleteRtmChannelPropertiesReq req)
        {
            Debug.Log("DeleteRtmChannelProperties is called in the android sdk");
            engine.Call("deleteRtmChannelProperties",
                DeleteRtmChannelPropertiesReq.ConvertDeleteRtmChannelPropertiesReq(req));
        }

        /**
         * 查询RTM频道历史消息
         *
         * @param req 查询RTM频道历史消息请求对象
         */
        public override void GetRtmChannelHistoryMessages(GetRtmChannelHistoryMessagesReq req)
        {
            Debug.Log("GetRtmChannelHistoryMessages is called in the android sdk");
            engine.Call("getRtmChannelHistoryMessages",
                GetRtmChannelHistoryMessagesReq.ConvertGetRtmChannelHistoryMessagesReq(req));
        }

        #endregion
    }
}
#endif